#include "ustate_machinie.h"


/*有限状态机初始化*/
void Create_ComUsart(Usart_Trm *Me,uint8_t set_h,uint8_t set_t)
{   
    static struct Usart_vtable vtable;

    my_memset(Me,0,sizeof(Usart_Trm));

    vtable.rx_buff=&Com_rxUsart_data;
    vtable.fram_deal=&Deal_com;
    vtable.fram_num=&Get_fram_num;   
    Me->c_vptr=&vtable;

    Me->head=set_h;
    Me->teal=set_t;
    Me->usart_status=STATUS_IDEL;
}

/*有限状态机读入缓存函数*/
void Com_rxUsart_data(Cir_queue * const QMe,Usart_Trm *const Me,uint8_t bydata)
{

    switch (Me->usart_status)
    {
        case STATUS_IDEL:
        if(bydata==Me->head)
        {
            Me->usart_status=STATUS_HEAD;
            Me->last_pos++;
        }
        
        else Me->usart_status=STATUS_END;
        break;
        
        case STATUS_HEAD:    
        if(bydata!=Me->teal) 
        {
            Me->usart_status=STATUS_DATA;
            Me->last_pos++;
        }

        else Me->usart_status=STATUS_END;
        break;
        
        case STATUS_DATA:
        if(bydata!=Me->teal&&!QMe->c_vptr->full(QMe)) 
        {
            Me->usart_status=STATUS_DATA;
            Me->last_pos++;
        }
        else if(bydata==Me->teal) 
        {
            Me->last_pos=0;/*成功接收到头和尾，没有错误数据*/
            Me->Uartx_frame++; /*队列中有效帧+1*/
            Me->usart_status=STATUS_IDEL;
        }

        else Me->usart_status=STATUS_END;
        break;

        case STATUS_END: break;

        default:Me->usart_status=STATUS_END;break;
    }

    if(Me->usart_status==STATUS_END)
    {
        QUEUE_TYPE temp;
        /*把出错数据取出,从尾取出*/
        while(Me->last_pos) 
        {
            QMe->c_vptr->tail_pop(QMe,&temp);
            Me->last_pos--;
        }
        Me->usart_status=STATUS_IDEL;
    }

    else
    {
        QMe->c_vptr->push(QMe,bydata);/*数据入队列*/
    }

}

/*实现两种命令方式，自定义根据有没有'='号自行判断命令类型*/

/*判断命令类型*/
static int Com_type(const char * const str)
{
    char *buf_ptr=(char *)str;
	int count = 0;
    
    /*内容为空*/
    if(*(buf_ptr+count)=='\0') return 0;	

	while (*(buf_ptr+count)!='='&&*(buf_ptr+count)!='\0')//'='是判断的位置，也是命令停止标志
	{
		count++;
	}

    if(*(buf_ptr+count)=='=') 
    {
       return count;
    }

	else 
    {
        return 0;
    }
}

/*读取取出1帧的内容，保存帧头和帧尾，返回读取到的内容*/
static char * Get_fram_data(Cir_queue *QMe,Usart_Trm *Me)
{
    static char buff[50],get_char;
    
    int i=0;
    my_memset(buff,0,sizeof(buff));

    while(Me->Uartx_frame!=0&&QMe->c_vptr->pop(QMe,&get_char)) 
    {
        if(get_char==')') 
        {
            Me->Uartx_frame--;
            break;
        }
        buff[i++]=get_char;
    }
    buff[i++]=')';
    return buff;
}

/*将命令放在尾部*/
void Com_tailpush(Cir_queue *QMe,Usart_Trm *Me,char const *get_str)
{
	Me->usart_status==STATUS_END;
	/*解决传入命令不完成的问题，比如原来数据：（111，还未接收完成（标记为错误，重新接收），插入就会变成（111（112）*/
    if(Me->last_pos!=0) 
    {
        QUEUE_TYPE temp;
        for(int i=Me->last_pos;i>0;i--) QMe->c_vptr->tail_pop(QMe,&temp);
        Me->usart_status=STATUS_IDEL;
        Me->last_pos=0;
    }
    /*把当前数据的帧头和帧尾放进列表尾部*/
    while(*get_str!='\0')
    {
        Me->c_vptr->rx_buff(QMe,Me,*get_str);/*存入数据进入缓冲区*/
        get_str++;
    }

    Me->c_vptr->rx_buff(QMe,Me,*get_str);/*将帧尾存入*/
}

/*返回缓存区的帧数*/
int Get_fram_num(Usart_Trm *Me)
{
    return Me->Uartx_frame;
}

/*返回0则为命令假，返回其他则为真，数据默认扩大1000倍，返回1则为命令模式*/
long Deal_com(Cir_queue *QMe,Usart_Trm *Me,const char *sdata)
{
	char com_buf[COMMAND_LEN_MAX]={0};//临时保存内容数据
    int eque_pos=0,back_data;

    float temp=0;
	char *get_string;

    int i=0;
    /*遍历队列中所有命令，找到符合命令的*/
    while (i<=Me->c_vptr->fram_num(Me))
    {
        i++;
        get_string=Get_fram_data(QMe,Me);    /*获取帧内容*/
        #ifdef CIRDEBUG
        printf("Get string is %s \n",get_string);
        #endif 
        /*遍历一遍找到了，则返回*/
        if(strncmp((const char *)get_string+1,sdata,strlen(sdata))==0)  break;
    
        Com_tailpush(QMe,Me,get_string);
    }
    
    /*遍历完都没有找到，丢弃当前帧，当前为最先插入的帧*/
    if(i==Me->c_vptr->fram_num(Me)+1) return 0;

    eque_pos=Com_type(++get_string);

    /*返回输入命令中的数字*/
	if(eque_pos!=0&&*get_string!='\0')
	{	
        /*把尾帧去掉*/
        for(int i=0;i<strlen(get_string)-(eque_pos+1);i++)
        {
             com_buf[i]=*(get_string+eque_pos+i+1);/*把等于号后面的全部数字保存*/
        }
		temp=atof(com_buf);/*字符串转换成为浮点型数字*/
        back_data=temp*1000;/*扩大100倍*/
        return back_data;
	}   
    /*符合命令，不反回参数*/
	else if(eque_pos==0&&*get_string!='\0')   return 1;
    /*其他情况*/
    else   return 0;
}
